﻿
//////////////////////////////////////////////////////////////////////////
//                                                                      //
//  Anybody can Use, Modify, Redistribute this code freely. If this     // 
//  module has been helpful to you then just leave a comment on Website //
//                                                                      //
//////////////////////////////////////////////////////////////////////////


using System;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using UniTAC.Properties;

namespace UniTAC
{
    public partial class AutoCompleteMenu : Form
    {

       public AutoCompleteMenu()
       {
           InitializeComponent();
           winHandle = GetForegroundWindow();  // Initialize winHandle with current foreground window

           // Check if word files are missing.
           if (!File.Exists(@"Words/A.txt") || !File.Exists(@"Words/B.txt")
               || !File.Exists(@"Words/C.txt") || !File.Exists(@"Words/D.txt")
               || !File.Exists(@"Words/E.txt") || !File.Exists(@"Words/F.txt")
               || !File.Exists(@"Words/GH.txt") || !File.Exists(@"Words/I.txt")
               || !File.Exists(@"Words/JKL.txt") || !File.Exists(@"Words/M.txt")
               || !File.Exists(@"Words/NO.txt") || !File.Exists(@"Words/P.txt")
               || !File.Exists(@"Words/QR.txt") || !File.Exists(@"Words/S.txt")
               || !File.Exists(@"Words/T.txt") || !File.Exists(@"Words/UV.txt")
               || !File.Exists(@"Words/WXYZ.txt"))
           {
               MessageBox.Show("Word Files Missing! Program will now exit.","Error!",MessageBoxButtons.OK,MessageBoxIcon.Error,MessageBoxDefaultButton.Button1);
               Environment.Exit(0);               // Show error message & exit program.
           }
           else timer1.Start(); // Processing events from Hooks involves message queue complexities.
       }                        // Timer has been used just to avoid that Mouse and Keyboard hooking                           
                                // and to keep things simple. 



        #region Event Handlers

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (Settings.Default.AutoSuggest == false)
            {
                this.Hide();
                label2.Text = "";
                return;
            }
            NoOfLetters = Settings.Default.LetterLimit;
            // If foreground window changes, clear suggestion list.
            if (GetForegroundWindow() != winHandle)
            {
                label2.Text = "";
                firstWord = "";
                winHandle = GetForegroundWindow();  // Store handle of new foreground window.
                return;
            }

            // Calculate Caret position
            EvaluateCaretPosition();

            // If caret is not present in the screen
            if ((posX == 0) && (posY == 5))
            {
                this.Visible = false;
                firstWord = "";
                return;
            }

            foreach (System.Int32 i in Enum.GetValues(typeof(Keys))) // Iterate through each key to know whether it was pressed or not
            {
                if (GetAsyncKeyState(i) == -32767)   // -32767(minimum value) indicates that key was pressed since we last called this function
                {
                    keyBuffer = Enum.GetName(typeof(Keys), i);  // Store current key value in keyBuffer

                    if (keyBuffer.Length == 1)
                        label2.Text += keyBuffer;  // Append each alphabet to label2
                    else if (keyBuffer == "ShiftKey" || keyBuffer == "RShiftKey"
                        || keyBuffer == "LShiftKey" || keyBuffer == "CapsLock"
                        || keyBuffer == "LButton")
                    { /* Do Nothing. */ }
                    else if (keyBuffer == "Back")
                    {
                        if (label2.Text.Length > 0)
                            label2.Text = label2.Text.Remove(label2.Text.Length - 1);
                    }
                    else if (keyBuffer == "Space")
                    {
                        if (Settings.Default.MultipleOccurrence == true)
                        {
                            if (firstWord == label2.Text && firstWord.Length > 0 && firstWord[0] != ' ')
                            {
                                for (icount = 0; icount <= label2.Text.Length; icount++)
                                    SendKeys.SendWait("{BS}");
                            }
                            else firstWord = label2.Text;
                        }
                        label2.Text = "";
                        listBox1.Items.Clear();
                    }
                    else
                    {
                        label2.Text = "";
                        firstWord = "";
                        listBox1.Items.Clear();
                    }
                }
                if (label2.Text.Length >= NoOfLetters)
                {
                    if (this.Visible == false)
                    {
                        ShowWindow(this.Handle, 8);
                        this.ActiveControl = listBox1;
                    }
                    AdjustUI(); // Adjust suggestion list according to the Caret
                }
                else this.Visible = false;
            }
        }


        private IntPtr HookCallback(int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam)
        {
            if (nCode >= 0)
            {
                switch (lParam.vkCode)
                {
                    // Down Arrow key
                    case 40: if ((int)wParam == WM_KEYDOWN || (int)wParam == WM_SYSKEYDOWN)
                        {
                            if (listBox1.SelectedIndex < listBox1.Items.Count - 1)
                                listBox1.SelectedIndex++;
                        }
                        return (System.IntPtr)1;
                    // Up Arrow key
                    case 38: if ((int)wParam == WM_KEYDOWN || (int)wParam == WM_SYSKEYDOWN)
                        {
                            if (listBox1.SelectedIndex > 0)
                                listBox1.SelectedIndex--;
                        }
                        return (System.IntPtr)1;
                    // Return button
                    case 13: if (listBox1.SelectedIndex != -1)
                        {
                            if ((int)wParam == WM_KEYUP || (int)wParam == WM_SYSKEYUP)
                                InsertWord();
                            return (System.IntPtr)1;
                        }
                        else return CallNextHookEx(hookID, nCode, wParam, ref lParam);
                    // Space bar
                    case 32: if (listBox1.SelectedIndex != -1)
                        {
                            if ((int)wParam == WM_KEYDOWN || (int)wParam == WM_SYSKEYDOWN)
                                InsertWord();
                            return CallNextHookEx(hookID, nCode, wParam, ref lParam);
                        }
                        else return CallNextHookEx(hookID, nCode, wParam, ref lParam);
                    /* case 8: if ((int)wParam == WM_KEYDOWN || (int)wParam == WM_SYSKEYDOWN)
                        {
                            label2.Text = label2.Text.Remove(label2.Text.Length - 1);
                        }
                        return CallNextHookEx(hookID, nCode, wParam, ref lParam); */
                    default: return CallNextHookEx(hookID, nCode, wParam, ref lParam);
                }
                // MessageBox.Show(lParam.vkCode.ToString());
            }
            return CallNextHookEx(hookID, nCode, wParam, ref lParam);
        }


        #endregion


        // Parameter which makes the form non-focusable
        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                cp.ExStyle |= (WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW);
                return cp;
            }
        }

           private void label1_Click(object sender, EventArgs e)
           {
               label2.Text = "";
               this.Hide();
           }

           private void ListUpdate(object sender, EventArgs e)
           {
               string[] words = null;
               if (label2.Text.Length >= NoOfLetters)
               {
                   string pat = "\\b" + label2.Text + "\\w*\\b";
                   Regex rx = new Regex(pat, RegexOptions.IgnoreCase);
                   if (label2.Text[0] == 'A')
                       words = File.ReadAllLines("Words/A.txt");
                   else if (label2.Text[0] == 'B')
                       words = File.ReadAllLines("Words/B.txt");
                   else if (label2.Text[0] == 'C')
                       words = File.ReadAllLines("Words/C.txt");
                   else if (label2.Text[0] == 'D')
                       words = File.ReadAllLines("Words/D.txt");
                   else if (label2.Text[0] == 'E')
                       words = File.ReadAllLines("Words/E.txt");
                   else if (label2.Text[0] == 'F')
                       words = File.ReadAllLines("Words/F.txt");
                   else if (label2.Text[0] == 'G' || label2.Text[0] == 'H')
                       words = File.ReadAllLines("Words/GH.txt");
                   else if (label2.Text[0] == 'I')
                       words = File.ReadAllLines("Words/I.txt");
                   else if (label2.Text[0] == 'J' || label2.Text[0] == 'K' || label2.Text[0] == 'L')
                       words = File.ReadAllLines("Words/JKL.txt");
                   else if (label2.Text[0] == 'M')
                       words = File.ReadAllLines("Words/M.txt");
                   else if (label2.Text[0] == 'N' || label2.Text[0] == 'O')
                       words = File.ReadAllLines("Words/NO.txt");
                   else if (label2.Text[0] == 'P')
                       words = File.ReadAllLines("Words/P.txt");
                   else if (label2.Text[0] == 'Q' || label2.Text[0] == 'R')
                       words = File.ReadAllLines("Words/QR.txt");
                   else if (label2.Text[0] == 'S')
                       words = File.ReadAllLines("Words/S.txt");
                   else if (label2.Text[0] == 'T')
                       words = File.ReadAllLines("Words/T.txt");
                   else if (label2.Text[0] == 'U' || label2.Text[0] == 'V')
                       words = File.ReadAllLines("Words/UV.txt");
                   else if (label2.Text[0] == 'W' || label2.Text[0] == 'X' || label2.Text[0] == 'Y' || label2.Text[0] == 'Z')
                       words = File.ReadAllLines("Words/WXYZ.txt");
                   listBox1.Items.Clear();
                   if (words.Length > 0)
                   {
                       foreach (String line in words)
                       {
                           if (rx.Match(line).Success)
                               listBox1.Items.Add(line);

                       }
                   }
               }
           }

           private void AutoCompleteMenu_VisibleChanged(object sender, EventArgs e)
           {
               if (this.Visible == true)
               {
                   proc = new HookHandlerDelegate(HookCallback);
                   using (Process curProcess = Process.GetCurrentProcess())
                   using (ProcessModule curModule = curProcess.MainModule)
                   {
                       hookID = SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
                   }
                   this.TopMost = true;
               }
               else UnhookWindowsHookEx(hookID);
           }

           private void listBox1_MouseClick(object sender, MouseEventArgs e)
           {
               if (listBox1.SelectedIndex != -1)
                   InsertWord();
           }
    }
}
